﻿/*
 * Json.h
 */
#ifndef __GDK_JSON_H__
#define __GDK_JSON_H__

#include <gdk/core/Types.h>
#include <gdk/core/String.h>
#include <gdk/core/convert.h>
#include <gdk/core/IO.h>
#include <gdk/core/Varint.h>
#include <math.h>
#include <map>


namespace gdk
{

class GDK_CORE_EXPORT JsonValue
{
	friend class Json;

public:
	typedef std::map<Varint, JsonValue> Array;
	typedef std::map<String, JsonValue> Members;
	enum ValueType {
		nullValue,     // 'null' value
		intValue,      // signed integer value
		uintValue,     // unsigned integer value
		realValue,     // double value
		booleanValue,  // bool value
		stringValue,   // string value
		arrayValue,    // array value (ordered list)
		objectValue,   // object value (collection of name/value pairs).
	};

private:
	union {
		int64_t		_int;
		uint64_t	_uint;
		double		_real;
		bool		_bool;
		String*		_string;
		Array*		_array;
		Members*	_members;
	}				_value;
	ValueType		_type;

public:
	__INLINE__ ~JsonValue(void) { clear(); }
	__INLINE__ JsonValue(int8_t value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(uint8_t value) { _type = uintValue; _value._uint = value; }
	__INLINE__ JsonValue(int16_t value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(uint16_t value) { _type = uintValue; _value._uint = value; }
	__INLINE__ JsonValue(int32_t value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(uint32_t value) { _type = uintValue; _value._uint = value; }
	__INLINE__ JsonValue(long value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(ulong_t value) { _type = uintValue; _value._uint = value; }
	__INLINE__ JsonValue(long long value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(unsigned long long value) { _type = uintValue; _value._uint = value; }
	/*
	__INLINE__ JsonValue(int64_t value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(uint64_t value) { _type = uintValue; _value._uint = value; }
	*/
	__INLINE__ JsonValue(double value) { _type = realValue; _value._real = value; }
	__INLINE__ JsonValue(float value) { _type = realValue; _value._real = value; }
	__INLINE__ JsonValue(bool value) { _type = booleanValue; _value._bool = value; }
	__INLINE__ JsonValue(char value) { _type = intValue; _value._int = value; }
	__INLINE__ JsonValue(const JsonValue &other) { _type = nullValue; this->operator= (other); }
	JsonValue(ValueType type = nullValue);
	JsonValue(const String &value);
	JsonValue(const Char *value);

	void clear(void);
	void swap(JsonValue &other);
	JsonValue& operator =(const JsonValue &other);
	__INLINE__ JsonValue& operator =(int8_t value)        { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(uint8_t value)       { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(int16_t value)       { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(uint16_t value)      { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(int32_t value)       { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(uint32_t value)      { JsonValue tmp(value); this->swap(tmp); return *this; }
	/*
	__INLINE__ JsonValue& operator =(int64_t value)       { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(uint64_t value)      { JsonValue tmp(value); this->swap(tmp); return *this; }
	*/
	__INLINE__ JsonValue& operator =(double value)        { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(float value)         { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(bool value)          { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(char value)          { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(long value)          { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(ulong_t value)       { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(long long value)          { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(unsigned long long value) { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(const String &value) { JsonValue tmp(value); this->swap(tmp); return *this; }
	__INLINE__ JsonValue& operator =(const Char *value)   { JsonValue tmp(value); this->swap(tmp); return *this; }

	bool operator ==(const JsonValue &other) const;
	__INLINE__ bool operator ==(int8_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(uint8_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(int16_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(uint16_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(int32_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(uint32_t value) const { return (*this == JsonValue(value)); }
	/*
	__INLINE__ bool operator ==(int64_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(uint64_t value) const { return (*this == JsonValue(value)); }
	*/
	__INLINE__ bool operator ==(double value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(float value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(bool value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(char value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(long value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(ulong_t value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(long long value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(unsigned long long value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(const String &value) const { return (*this == JsonValue(value)); }
	__INLINE__ bool operator ==(const Char *value) const { return (*this == JsonValue(value)); }

	__INLINE__ bool operator !=(const JsonValue &other) const { return !(*this == other);}
	__INLINE__ bool operator !=(int8_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(uint8_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(int16_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(uint16_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(int32_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(uint32_t value) const { return !(*this == JsonValue(value)); }
	/*
	__INLINE__ bool operator !=(int64_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(uint64_t value) const { return !(*this == JsonValue(value)); }
	*/
	__INLINE__ bool operator !=(double value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(float value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(bool value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(char value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(long value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(ulong_t value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(long long value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(unsigned long long value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(const String &value) const { return !(*this == JsonValue(value)); }
	__INLINE__ bool operator !=(const Char *value) const { return !(*this == JsonValue(value)); }

#if defined(_M_X64) || defined(__x86_64__) || defined(__IOS__) || defined(_WIN32)// || defined(__ANDROID__)
	__INLINE__ JsonValue& operator[](int index) { return this->operator[](ssize_t(index)); }
	__INLINE__ const JsonValue& operator[](int index) const { return this->operator[](ssize_t(index)); }
#endif

	JsonValue& operator[](ssize_t index);
	const JsonValue& operator[](ssize_t index) const;

	JsonValue& operator[](const Char* key);
	const JsonValue& operator[](const Char* key) const;

	JsonValue& operator[](const String& key);
	const JsonValue& operator[](const String& key) const;

	__INLINE__ const Members& getMembers(void) const { return (*_value._members); }

	float asFloat(void) const;
	double asDouble(void) const;
	bool asBool(void) const;
	String asString(void) const;

	operator String () const { return asString(); }
	__INLINE__ operator float () const { return asFloat(); }
	__INLINE__ operator double () const { return asDouble(); }
	__INLINE__ operator bool () const { return asBool(); }
	__INLINE__ operator char () const { return asInt8(); }
	__INLINE__ operator long () const {
		switch (sizeof(long)) {
		case 8: return static_cast<long>(asInt64());
		default: break;
		}
		return asInt32();
	}
	__INLINE__ operator ulong_t () const {
		switch (sizeof(ulong_t)) {
		case 8: return static_cast<ulong_t>(asUInt64());
		default: break;
		}
		return asUInt32();
	}
	__INLINE__ operator long long () const { return asInt64(); }
	__INLINE__ operator unsigned long long () const { return asUInt64(); }
	__INLINE__ operator int8_t () const  { return asInt8(); }
	__INLINE__ operator int16_t () const { return asInt16(); }
	__INLINE__ operator int32_t () const { return asInt32(); }
	__INLINE__ operator uint8_t () const  { return asUInt8(); }
	__INLINE__ operator uint16_t () const { return asUInt16(); }
	__INLINE__ operator uint32_t () const { return asUInt32(); }

	__INLINE__ ValueType type(void) const { return _type; }
	__INLINE__ bool isNull(void) const { return _type == nullValue; }
	__INLINE__ bool isBool(void) const { return _type == booleanValue; }
	__INLINE__ bool isNumber(void) const { return _type == realValue || isInt64() || isUInt64(); }
	__INLINE__ bool isString(void) const { return _type == stringValue; }
	__INLINE__ bool isArray(void) const { return _type == arrayValue; }
	__INLINE__ bool isObject(void) const { return _type == objectValue; }

	ssize_t size(void) const;
	bool empty(void) const;


#define DECLARE_JSON_INT_FUNC_XXX(type, name, min, max) \
	/*__INLINE__ operator type () const { return as##name(); }*/ \
	type as##name(void) const \
	{ \
		switch (_type) { \
		case intValue: \
			if (!is##name()) \
				 Log::warning(__TEXT__("intValue out of ") __TEXT__(#name) __TEXT__(" range")); \
			return type(_value._int); \
		case uintValue: \
			if (!is##name()) \
				Log::warning(__TEXT__("uintValue out of ") __TEXT__(#name) __TEXT__(" range")); \
			return type(_value._uint); \
		case realValue: \
			if (!(_value._real >= min && _value._real <= max)) \
				Log::warning(__TEXT__("double out of ") __TEXT__(#name) __TEXT__(" range"));\
			return type(_value._real); \
		case booleanValue: \
			return _value._bool ? 1 : 0; \
		case stringValue: \
			return type(__atoi64(*_value._string));\
		case arrayValue: \
		case objectValue: \
			Log::warning(__TEXT__("Value is not convertible to ") __TEXT__(#name));\
		default: break;\
		} \
		return 0; \
	} \
	bool is##name(void) const \
	{ \
		switch (_type) { \
		case intValue: \
			return _value._int >= min && _value._int <= static_cast<int64_t>(max); \
		case uintValue: \
			return _value._uint <= static_cast<uint64_t>(max); \
		case realValue: { \
			double integral_part; \
			return _value._real >= min && _value._real <= max && (modf(_value._real, &integral_part) == 0.0); \
			} \
		default: break;\
		} \
		return false; \
	}
#define DECLARE_JSON_INT_FUNC(bits) \
	DECLARE_JSON_INT_FUNC_XXX(int##bits##_t, Int##bits, INT##bits##_MIN, INT##bits##_MAX) \
	DECLARE_JSON_INT_FUNC_XXX(uint##bits##_t, UInt##bits, 0, UINT##bits##_MAX)

	DECLARE_JSON_INT_FUNC(8)
	DECLARE_JSON_INT_FUNC(16)
	DECLARE_JSON_INT_FUNC(32)
	DECLARE_JSON_INT_FUNC(64)

public:
	template<typename TyIs> friend TyIs& operator >>(TyIs &is, JsonValue &o) __THROW1;
	template<typename TyOs> friend TyOs& operator <<(TyOs &os, const JsonValue &o) __THROW1;
};


template<typename TyIs>
TyIs& operator >>(TyIs &is, JsonValue &o) __THROW1
{
	o.clear();

	char t;
	is >> t;

	switch (t) {
	case JsonValue::nullValue:     // 'null' value
		break;
	case JsonValue::intValue:      // signed integer value
	case JsonValue::uintValue:     // unsigned integer value
		{
			Varint64 i;
			is >> i;

			JsonValue v((JsonValue::ValueType)t);
			v._value._int = i;
			o.swap(v);
		}
		break;
	case JsonValue::realValue:     // double value
		{
			double v;
			is >> v;
			o = v;
		}
		break;
	case JsonValue::booleanValue:  // bool value
		{
			bool v;
			is >> v;
			o = v;
		}
		break;
	case JsonValue::stringValue:   // string value
		{
			JsonValue v(JsonValue::stringValue);
			is >> (*v._value._string);
			o.swap(v);
		}
		break;
	case JsonValue::arrayValue:    // array value (ordered list)
		{
			JsonValue v(JsonValue::arrayValue);
			is >> (*v._value._array);
			o.swap(v);
		}
		break;
	case JsonValue::objectValue:   // object value (collection of name/value pairs).
		{
			JsonValue v(JsonValue::objectValue);
			is >> (*v._value._members);
			o.swap(v);
		}
		break;
	}
	return is;
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const JsonValue &o) __THROW1
{
	char t = char(o._type);
	os << t;

	switch (o._type) {
	case JsonValue::nullValue:     // 'null' value
		break;
	case JsonValue::intValue:      // signed integer value
	case JsonValue::uintValue:     // unsigned integer value
		{
			Varint64 v(o._value._int);
			os << v;
		}
		break;
	case JsonValue::realValue:     // double value
		{
			os << o._value._real;
		}
		break;
	case JsonValue::booleanValue:  // bool value
		{
			os << o._value._bool;
		}
		break;
	case JsonValue::stringValue:   // string value
		{
			os << (*o._value._string);
		}
		break;
	case JsonValue::arrayValue:    // array value (ordered list)
		{
			os << (*o._value._array);
		}
		break;
	case JsonValue::objectValue:   // object value (collection of name/value pairs).
		{
			os << (*o._value._members);
		}
		break;
	}
	return os;
}


//////////////////////////////////////////////////////////
class GDK_CORE_EXPORT Json
{
private:
	static bool write_value(const JsonValue& jsonValue, Output* out, int indent);

public:
	static const Char* parseValue(const Char *text, JsonValue &jsonValue);
	static bool writeValue(const JsonValue& jsonValue, Output* out, bool indent = false);

	static String convertToString(const JsonValue& jsonValue, bool indent = false);

	static bool read(JsonValue& jsonValue, Input* in);
	static bool write(JsonValue& jsonValue, Output* out, bool indent = false);

	static bool load(JsonValue& jsonValue, const String &fileName);
	static bool save(JsonValue& jsonValue, const String &fileName, bool indent = false);
};




}//namespace gdk


#endif //__GDK_JSON_H__
